package cn.schoolwow.quickdao.module.database.dml.instance.flow.insert.get;

import cn.schoolwow.quickdao.domain.entity.Entity;
import cn.schoolwow.quickdao.domain.entity.Property;
import cn.schoolwow.quickdao.module.database.dml.common.domain.ManipulationOption;
import cn.schoolwow.quickdao.module.database.dml.instance.flow.insert.common.DistinguishBySinglePropertyFlow;
import cn.schoolwow.quickdao.module.database.dml.instance.flow.insert.common.DistinguishByUniqueKeyFlow;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;

import java.util.*;

public class DistinguishExistInstanceFlow implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        setExistInstanceSet(flowContext);
        setNotExistInstanceSet(flowContext);

        Set<Object> existInstanceSet = (Set<Object>) flowContext.getData("existInstanceSet");
        Set<Object> notExistInstanceSet = (Set<Object>) flowContext.getData("notExistInstanceSet");
        if(existInstanceSet.isEmpty()&&notExistInstanceSet.isEmpty()){
            throw new IllegalArgumentException("逻辑执行异常!存在实例和不存在实例个数都为0!");
        }
        flowContext.putTemporaryData("existInstances", existInstanceSet.toArray(new Object[0]));
        flowContext.putTemporaryData("notExistInstances", notExistInstanceSet.toArray(new Object[0]));
        flowContext.removeData("existInstanceSet");
        flowContext.removeData("notExistInstanceSet");

        {
            List existInstanceList = new ArrayList();
            existInstanceList.addAll(existInstanceSet);
            flowContext.putTemporaryData("existInstanceList", existInstanceList);
        }
        {
            List notExistInstanceList = new ArrayList();
            notExistInstanceList.addAll(notExistInstanceSet);
            flowContext.putTemporaryData("notExistInstanceList", notExistInstanceList);
        }
    }

    @Override
    public String name() {
        return "区分实例是否存在";
    }

    private void setExistInstanceSet(FlowContext flowContext){
        Entity entity = (Entity) flowContext.checkData("entity");
        ManipulationOption manipulationOption = flowContext.checkInstanceData(ManipulationOption.class);

        Set<Object> existInstanceSet = new HashSet<>();
        flowContext.putTemporaryData("existInstanceSet", existInstanceSet);

        if(!manipulationOption.uniqueFieldNames.isEmpty()){
            if(manipulationOption.uniqueFieldNames.size()==1){
                Property singleProperty = entity.getPropertyByFieldNameOrColumnName(manipulationOption.uniqueFieldNames.iterator().next());
                flowContext.startFlow(new DistinguishBySinglePropertyFlow())
                        .putCurrentCompositeFlowData("singleProperty", singleProperty)
                        .execute();
            }else{
                List<Property> uniquePropertyList = new ArrayList<>();
                for(String uniqueFieldName:manipulationOption.uniqueFieldNames){
                    Property property = entity.getPropertyByFieldNameOrColumnName(uniqueFieldName);
                    uniquePropertyList.add(property);
                }
                flowContext.startFlow(new DistinguishByUniqueKeyFlow())
                        .putCurrentCompositeFlowData("uniquePropertyList", uniquePropertyList)
                        .execute();
            }
        }else if(entity.uniqueProperties.size()>0){
            if(entity.uniqueProperties.size()==1){
                flowContext.startFlow(new DistinguishBySinglePropertyFlow())
                        .putCurrentCompositeFlowData("singleProperty", entity.uniqueProperties.get(0))
                        .execute();
            }else{
                flowContext.startFlow(new DistinguishByUniqueKeyFlow())
                        .putCurrentCompositeFlowData("uniquePropertyList", entity.uniqueProperties)
                        .execute();
            }
        }else if(null!=entity.id){
            flowContext.startFlow(new DistinguishBySinglePropertyFlow())
                    .putCurrentCompositeFlowData("singleProperty", entity.id)
                    .execute();
        }
    }

    private void setNotExistInstanceSet(FlowContext flowContext){
        Set<Object> existInstanceSet = (Set<Object>) flowContext.getData("existInstanceSet");
        Object[] instances = (Object[]) flowContext.checkData("instances");

        if(existInstanceSet.isEmpty()){
            flowContext.putData("notExistInstanceSet", new HashSet<>(Arrays.asList(instances)));
            return;
        }

        Set<Object> notExistInstanceSet = new HashSet<>();
        for(int i=0;i<instances.length;i++){
            if(!existInstanceSet.contains(instances[i])){
                notExistInstanceSet.add(instances[i]);
            }
        }
        flowContext.putData("notExistInstanceSet", notExistInstanceSet);
    }

}
